package com.shiguiwu.springboot3.rabbitmq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.HashMap;

/**
 * @description: 配置
 * @author: stone
 * @date: Created by 2023/11/17 21:22
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springboot3.rabbitmq.config
 */
@Slf4j
@Configuration
public class RabbitMQConfig {

    private RabbitTemplate rabbitTemplate;

    @Primary
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(messageConverter());
        initRabbitTemplate();
        return rabbitTemplate;
    }


    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * A\设置消息确认机制
     * B\设置交换机确认
     * 对象创建后执行
     */
    public void initRabbitTemplate() {

        /**
         * 三个参数
         * 1、消息唯一关联数据 correlationData
         * 2、消息是否成功收到 ack
         * 3、失败的原因 cause 如果么有就是null
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (!ack) {
                log.error("消息发送到交换机失败，消息标识：{},错误原因:{}", correlationData, cause);
                CorrelationDataExt ext = (CorrelationDataExt) correlationData;
                this.rabbitTemplate.convertAndSend("test_ex", "test_key", ext.getData(),correlationData);
            }
        });

        /**
         * 注意，消息投递失败才回调的函数
         * 1、消息本身
         * 2、回调的状态码
         * 3、消息错误的原因
         * 4、交换机
         * 5、路由键
         */
        rabbitTemplate.setReturnsCallback(rm -> {
            log.error("消息发送失败,消息未达到队列，消息本身：{}，消息的状态：{}，错误原因:{}，消息的交换机：{}，消息的路由键：{}",
                    rm.getMessage(), rm.getReplyCode(), rm.getReplyText(), rm.getExchange(), rm.getRoutingKey());
        });
    }




    /* 容器中的Queue、Exchange、Binding 会自动创建（在RabbitMQ）不存在的情况下 */


    /**
     * 普通队列
     * @return
     */
    @Bean
    public Queue TestQueue() {
        return new Queue("test", true, false, false);
    }

    /**
     * 订单交换机
     * @return
     */
    @Bean
    public Exchange testExchange() {
        return new TopicExchange("test_ex", true, false);
    }

   @Bean
    public Exchange testExchange2() {
        return new DirectExchange("test_ex11", true, false);
    }


    @Bean
    public Queue queueTopic2() {
        return new Queue("queue_topic2");
    }
    @Bean
    public Queue queue3() {
        return new Queue("queue_topic4");
    }

    /**
     * 延迟队列，又叫死信队列 “
     *
     * @return
     */
    @Bean
    public Queue delayQueue() {
        HashMap<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", "test_ex");
        arguments.put("x-dead-letter-routing-key", "test_ex.dead");
        // 消息过期时间 2分钟
        arguments.put("x-message-ttl", 60000);
        return new Queue("delayQueue", true, false, false, arguments);
    }

    /**
     * 往死信队列发消息的绑定
     * @return
     */
    @Bean
    public Binding bindingToDead() {
        return new Binding("delayQueue",
                Binding.DestinationType.QUEUE,
                "test_ex",
                "shiguiwu_key.1",
                null);
    }

    /**
     * 死信队列过期以后，发消息的绑定
     * @return
     */
    @Bean
    public Binding bindingDeadToQu() {
        return new Binding("queue_topic2",
                Binding.DestinationType.QUEUE,
                "test_ex",
                "test_ex.dead",
                null);
    }



    @Bean
    public Binding testBinding() {

        return new Binding("test",
                Binding.DestinationType.QUEUE,
                "test_ex",
                "test_key.#",
                null);
    }

    @Bean
    public Binding testBinding2() {
        return new Binding("queue_topic4",
                Binding.DestinationType.QUEUE,
                "test_ex11",
                "test_key.test",
                null);
    }

    @Bean
    public Binding testBinding1() {
        return BindingBuilder.bind(queueTopic2()).to(testExchange())
                .with("test_key.*").noargs();
    }

}
